﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

using ICSharpCode;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;

namespace Common
{


    public static class Zip
    {
        
        public static MemoryStream ExtractZipFile(string archiveFilenameIn)
        {
            ZipFile zf = null;
            try
            {
                FileStream fs = File.OpenRead(archiveFilenameIn);
                zf = new ZipFile(fs);
        

                foreach (ZipEntry zipEntry in zf)
                {
                    if (!zipEntry.IsFile)
                    {
                        continue;           // Ignore directories
                    }
                    String entryFileName = zipEntry.Name;
                    // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
                    // Optionally match entrynames against a selection list here to skip as desired.
                    // The unpacked length is available in the zipEntry.Size property.

                    byte[] buffer = new byte[4096];     // 4K is optimum
                    Stream zipStream = zf.GetInputStream(zipEntry);

                    // Manipulate the output filename here as desired.
                    //String fullZipToPath = Path.Combine(outFolder, entryFileName);
                    //string directoryName = Path.GetDirectoryName(fullZipToPath);
                    //if (directoryName.Length > 0)
                      //  Directory.CreateDirectory(directoryName);

                    // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
                    // of the file, but does not waste memory.
                    // The "using" will close the stream even if an exception occurs.

                    MemoryStream ms = new MemoryStream();
                    StreamUtils.Copy(zipStream, ms, buffer);

                    return ms;

                }
            }
            finally
            {
                if (zf != null)
                {
                    zf.IsStreamOwner = true; // Makes close also shut the underlying stream
                    zf.Close(); // Ensure we release resources
                }
            }

            return null;
        }
        
        /*
        public static void ExtractZipFile(string archiveFilenameIn, string outFolder)
        {
            ZipFile zf = null;
            try
            {
                FileStream fs = File.OpenRead(archiveFilenameIn);
                zf = new ZipFile(fs);

                foreach (ZipEntry zipEntry in zf)
                {
                    if (!zipEntry.IsFile)
                    {
                        continue;           // Ignore directories
                    }
                    String entryFileName = zipEntry.Name;
                    // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
                    // Optionally match entrynames against a selection list here to skip as desired.
                    // The unpacked length is available in the zipEntry.Size property.

                    byte[] buffer = new byte[4096];     // 4K is optimum
                    Stream zipStream = zf.GetInputStream(zipEntry);

                    // Manipulate the output filename here as desired.
                    //String fullZipToPath = Path.Combine(outFolder, entryFileName);
                    //string directoryName = Path.GetDirectoryName(fullZipToPath);
                    //if (directoryName.Length > 0)
                      //  Directory.CreateDirectory(directoryName);

                    // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
                    // of the file, but does not waste memory.
                    // The "using" will close the stream even if an exception occurs.
                    
                    using (MemoryStream streamWriter = (MemoryStream)File.Create(fullZipToPath))
                    {
                        StreamUtils.Copy(zipStream, streamWriter, buffer);
                    }


                    
                }
            }
            finally
            {
                if (zf != null)
                {
                    zf.IsStreamOwner = true; // Makes close also shut the underlying stream
                    zf.Close(); // Ensure we release resources
                }
            }
        }
        */
        public static MemoryStream ExtractZipFile(string archiveFilenameIn, string password)
        {

            ZipFile zf = null;
            try
            {
                //MemoryStream fs = File.OpenRead(archiveFilenameIn);
                MemoryStream memStream = new MemoryStream();

                using (FileStream fileStream = File.OpenRead(archiveFilenameIn))
                {
                    memStream.SetLength(fileStream.Length);
                    fileStream.Read(memStream.GetBuffer(), 0, (int)fileStream.Length);
                }

                zf = new ZipFile(memStream);

                if (!String.IsNullOrEmpty(password))
                {
                    zf.Password = password;     // AES encrypted entries are handled automatically
                }

                foreach (ZipEntry zipEntry in zf)
                {
                    if (!zipEntry.IsFile)
                    {
                        continue;           // Ignore directories
                    }
                    String entryFileName = zipEntry.Name;
                    // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
                    // Optionally match entrynames against a selection list here to skip as desired.
                    // The unpacked length is available in the zipEntry.Size property.

                    byte[] buffer = new byte[4096];     // 4K is optimum
                    Stream zipStream = zf.GetInputStream(zipEntry);

                    // Manipulate the output filename here as desired.
                    //String fullZipToPath = Path.Combine(outFolder, entryFileName);
                    //string directoryName = Path.GetDirectoryName(fullZipToPath);
                    //if (directoryName.Length > 0)
                    //Directory.CreateDirectory(directoryName);

                    // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
                    // of the file, but does not waste memory.
                    // The "using" will close the stream even if an exception occurs.
                    using (MemoryStream streamWriter = new MemoryStream())
                    {
                        StreamUtils.Copy(zipStream, streamWriter, buffer);
                        return streamWriter;
                    }

                }
            }
            finally
            {
                if (zf != null)
                {
                    zf.IsStreamOwner = true; // Makes close also shut the underlying stream
                    zf.Close(); // Ensure we release resources
                }
            }
            return null;
        }

        
        public static MemoryStream MemExtract(string file)
        {

            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            System.Text.StringBuilder sb = new StringBuilder();

            ICSharpCode.SharpZipLib.Zip.ZipInputStream zis = new ICSharpCode.SharpZipLib.Zip.ZipInputStream(new System.IO.FileStream(file, System.IO.FileMode.Open));
            ICSharpCode.SharpZipLib.Zip.ZipEntry entry = null;
            while ((entry = zis.GetNextEntry()) != null)
            {
                //if (entry.Name.ToLower() == "FILE YOU ARE SEARCHING FOR EXTRACT")
                //{
                    //lets extract
                    //System.IO.FileStream fs = new System.IO.FileStream("PATH WHERE TO EXTRACT" + entry.Name, System.IO.FileMode.Append);

                    int size = 2048;
                    byte[] data = new byte[2048];
                    while (true)
                    {
                        size = zis.Read(data, 0, data.Length);
                        if (size > 0)
                        {
                            ms.Write(data, 0, size);
                        }
                        else
                        {
                            break;
                        }
                    }

                    //fs.Close();

                    //fs.Dispose();
                
            }

            return  ms;

        }
    }
}
